import { Algorithm } from '../../constants/Algorithm';
import { Constant } from '../../constants/Constant';
import { Messages } from '../../constants/Messages';

const { ccclass, property, menu } = cc._decorator;

const EaseAction = Constant.EaseAction;
const EaseFunction = Constant.EaseFunction;
const RunningState = Constant.RunningState;

@ccclass
@menu("Tweens/WhirlingThing")
export default class WhirlingThing extends cc.Component {


    @property({ type: cc.Enum(Constant.RunningState) })
    mode: Constant.RunningState = RunningState.Idle;
    @property({type: cc.Enum(Constant.Direction)})
    direction: Constant.Direction = Constant.Direction.Left;
    @property
    isConstantSpeed: boolean = false;
    @property
    _easeAction: Constant.EaseAction = EaseAction.easeCubicOut;
    @property({ type: cc.Enum(EaseAction), visible: function () { return !this.isConstantSpeed } })
    get easeAction(): Constant.EaseAction {
        return this._easeAction;
    }
    set easeAction(action: Constant.EaseAction) {
        this._easeAction = action;
        this._easeFunction = Algorithm[EaseFunction[action]];
    }
    @property
    isLoop: boolean = false;
    @property
    isAuto: boolean = false;
    @property
    cycleTimes: number = 1;
    @property
    callTag: number = 0;
    @property([cc.Vec2])
    whirlingItems: cc.Vec2[] = [cc.v2(0, 0), cc.v2(1, 360), cc.v2(0, 0)]

    _tikPast: number = 0;
    _itemCursor: number = 0;
    _angleOff: number = 0;
    _anglePrevious: number = 0;
    _numPer: number = 0;
    _angleFoward: number = 1;
    _cycleTimes: number = 0;

    _easeFunction: Function = null;

    onLoad() {
        this._initEvents();
        this._easeFunction = Algorithm[EaseFunction[this._easeAction]];
    }

    onEnable() {
        this.isAuto ? this.mode = Constant.RunningState.Running : null;
        this.cycleTimes < 1 ? this.cycleTimes = 1 : null;
        this._cycleTimes = this.cycleTimes;;
        this._itemCursor = 0;;
        this._tikPast = 0;
        this._anglePrevious = this.node.angle;
    }

    start() {}

    _initEvents() {
        this.node.on(Messages.Nodes.StateChangePause, () => {
            this.mode = Constant.RunningState.Paused;
        }, this);
        this.node.on(Messages.Nodes.StateChangeRun, (callTag?: number, reset: boolean = true) => {
            reset && this.onEnable();
            if (callTag == null || callTag == this.callTag) {
                this.mode = Constant.RunningState.Running;
            }
        }, this);
        this.node.on(Messages.Nodes.StateChangeStop, () => {
            this.mode = Constant.RunningState.Stop;
        }, this);
        this.node.on(Messages.Nodes.ThingSetChangeWhirling, (items) => {
            items ? this.whirlingItems = items : null;
            this._itemCursor = 0;
            this._tikPast = 0;
        }, this);
    }

    protected update(dt: number): void {
        this._calculate(dt);
    }

    _calculate(dt: number = 0) {
        switch (this.mode) {
            case Constant.RunningState.Running:
                if (this.whirlingItems.length <= 0) return;
                switch (this.direction) {
                    case Constant.Direction.Left: this._angleFoward = 1; break;
                    case Constant.Direction.Right: this._angleFoward = -1; break
                }
                this._tikPast = this._tikPast + dt;
                this._numPer = this.isConstantSpeed ? this._tikPast / this.whirlingItems[this._itemCursor].x :
                    this._easeFunction(this._tikPast / this.whirlingItems[this._itemCursor].x);
                this._angleOff = this._numPer * (this.whirlingItems[this._itemCursor].y - this._anglePrevious) * this._angleFoward;
                break;
            default: return;
        }
        this.node.angle = this._anglePrevious + this._angleOff;

        if (this._tikPast >= this.whirlingItems[this._itemCursor].x) {
            this.node.angle = this.whirlingItems[this._itemCursor].y;
            this._tikPast = this._tikPast - this.whirlingItems[this._itemCursor].x;
            this._anglePrevious = this.whirlingItems[this._itemCursor].y;
            this._itemCursor++;
        }

        if (this._itemCursor >= this.whirlingItems.length) {
            this._itemCursor = 0;
            if (this.isLoop) {
                return;
            }
            this._cycleTimes--;
            if (this._cycleTimes < 1) {
                this.mode = Constant.RunningState.Idle;
                return;
            }
        }
    }
}
